<template>
  <div class="trend" ref="parent">
    <button @click="clickLoad1">DATASET 1</button>
    <button @click="clickLoad2">DATASET 2</button>
    <button @click="clickLoad3">DATASET 3</button>
    <button @click="clickLoad4">DATASET 4</button>
    <div ref="ele" class="canvas-parent"></div>
  </div>
</template>
<script>
import _ from "lodash";
import randomstring from "randomstring";
import echarts from "echarts";
import color from "color";
import Debug from "debug";
import axios from "axios";
// import Data_i50_max from "../../public/i50_max";
const dbg = Debug("Trend.vue");
dbg.enabled = true;

_;
// debugger

export default {
  name: "TrendLineGraph",
  data() {
    return {
      error_hint: "NO DATA",
      chart: echarts.init(document.createElement("null")),
      attrs: [],
      line_points: [],
      wugong_data: [],
    };
  },
  computed: {
    trend_colors() {
      return ["#0a9650", "#c33b37"];
    },
    gray_colors() {
      return ["#DCDCDC", "#808080", "#C7C7C7"];
    },
    font_size() {
      return 11;
    },
    MAX_CVs() {
      return this.wugong_data.map((arr) => {
        return _.max(arr.map((e) => e["cv"]));
      });
    },
    MIN_CVs() {
      return this.wugong_data.map((arr) => {
        return _.min(arr.map((e) => e["cv"]));
      });
    },
    MAX_SKEWs() {
      return this.wugong_data.map((arr) => {
        return _.max(arr.map((e) => e["skew"]));
      });
    },
    MIN_SKEWs() {
      return this.wugong_data.map((arr) => {
        return _.min(arr.map((e) => e["skew"]));
      });
    },
    func_cv2value() {
      let _this = this;
      /**
       * @param {Number} cv
       * @param {Number} i -- index of attr,也许会随着index而变化
       * @description 如何把CV的值映射到Y轴上的值?
       */
      function __cv(cv, i = 0) {
        // debugger
        // let max_jueduizhi = _.max([_this.MAX_CVs[i],0-_this.MIN_CVs[i]])
        let line_point_values = this.line_points[i].map((e) => e["value"]);
        let max_pointvalue = _.max(line_point_values);
        let min_pointvalue = _.min(line_point_values);
        let order = _this.orderOfMagnitude(max_pointvalue - min_pointvalue);
        let s = Math.ceil((max_pointvalue - min_pointvalue) / order) * order;

        return (
          ((cv - _this.MIN_CVs[i]) / (_this.MAX_CVs[i] - _this.MIN_CVs[i])) *
          s *
          1
        );
      }
      return __cv;
    },
    func_skew2value() {
      let _this = this;
      /**
       * @param {Number} skew
       * @param {Number} i -- index of attr
       */
      function __skew(skew, i = 0) {
        let max_jueduizhi = _.max([_this.MAX_SKEWs[i], -_this.MIN_SKEWs[i]]);
        return (skew / max_jueduizhi) * _this.ORDERs_OF_LINE[i];
      }
      return __skew;
    },
    MIN_MAX_ORDER() {
      // debugger
      return this.line_points.map((line_arr, line_index) => {
        let minB_Cv = _.min(
          this.wugong_data[line_index].map((w) => {
            // debugger;
            let e = line_arr.find((x) => x["test_id"] == w["test_id"]);
            if (!e) {
              debugger;
              w;
            }
            return e["value"] - this.func_cv2value(w["cv"], line_index) / 2;
          })
        );
        let maxB_Cv = _.max(
          this.wugong_data[line_index].map((w) => {
            let e = line_arr.find((x) => x["test_id"] == w["test_id"]);
            return e["value"] + this.func_cv2value(w["cv"], line_index) / 2;
          })
        );

        let min = _.min([minB_Cv]);
        let max = _.max([maxB_Cv]);
        return {
          __debug: {
            minB_Cv,
            // minB_skew,
            maxB_Cv,
            // maxB_skew
          },
          min: min,
          max: max,
          order: this.orderOfMagnitude(max - min),
        };
        return "null";
      });
    },
    orderOfMagnitude() {
      return function convertOrderOfMagnitude(n) {
        var order = Math.floor(Math.log(n) / Math.LN10 + 0.000000001); // because float math sucks like that
        return Math.pow(10, order);
      };
    },
    __debug_ORDERS_of_LINE() {
      return this.line_points.map((arr, i) => {
        let max = _.max(arr.map((e) => e["value"]));
        let min = _.min(arr.map((e) => e["value"]));
        return { min, max, order: this.orderOfMagnitude((max - min) * 1.5) };
      });
    },
    ORDERs_OF_LINE() {
      return this.line_points.map((arr, i) => {
        // let max = _.max(arr.map(e => e["value"]));
        // let min = _.min(arr.map(e => e["value"]));
        return this.__debug_ORDERS_of_LINE[i]["order"];
      });
    },
    calced_lengthOfLinePoints() {
      let lengthOfLinePoints;
      try {
        if (this.line_points.length) {
          let max_test_id =
            this.line_points[0][this.line_points[0].length - 1]["test_id"];
          let order = this.orderOfMagnitude(max_test_id);

          lengthOfLinePoints = max_test_id;
        } else {
          lengthOfLinePoints = 250001;
        }
        return lengthOfLinePoints;
      } catch (e) {
        return 1;
      }
    },
    OFFSETS() {
      if (this.MIN_MAX_ORDER) {
        return this.MIN_MAX_ORDER.map((mmo, i) => {
          if (mmo.min < 0) {
            let off = -mmo.min;
            off = Math.ceil(off / mmo.order) * mmo.order;
            return off;
          }
          return 0;
        });
      }
      return null;
    },
    opt_xAxis() {
      return [
        {
          type: "category",
          show: false,
          data: (($) => {
            if (this.line_points.length) {
              if (this.line_points[0].length >= 2) {
                let arr = this.line_points[0];
                let last = arr[arr.length - 1];
                let order = this.orderOfMagnitude(
                  last["test_id"] - arr[arr.length - 2]["test_id"]
                );
                let end_test_id = Math.ceil(last["test_id"] / order) * order;
                let start_test_id =
                  Math.floor(arr[0]["test_id"] / order) * order;
                return _.range(start_test_id, end_test_id);
              }
            }

            return _.range(0, this.calced_lengthOfLinePoints);
          })(),
          splitLine: {
            show: false,
          },
          gridIndex: 0,
          axisLine: {
            onZero: false,
            lineStyle: {
              fontSize: 12,
              color: this.gray_colors[0],
            },
          },
          axisTick: {
            // interval: 10000,
            alignWithLabel: true, //保证刻度线和标签对齐
          },
          axisLabel: {
            // interval: 10000,
            color: this.gray_colors[1],
            fontSize: this.font_size,
            // interval: 49999
          },
          name: "Test No.",
          nameGap: 34,
          nameLocation: "center",
          nameTextStyle: {
            color: this.gray_colors[1],
            textShadowColor: "transparent",
            textShadowBlur: 0,
            textShadowOffsetY: 14,
            fontSize: this.font_size,
          },

          position: "bottom",
        },
        {
          type: "category",
          gridIndex: 1,
          data: _.range(0, this.calced_lengthOfLinePoints),
        },
      ];
    },
    opt_yAxis() {
      let vue = this;
      return this.attrs
        .map((attr, i) => {
          return {
            type: "value",
            axisLine: {
              onZero: false,
              lineStyle: {
                color: this.gray_colors[0],
              },
            },
            splitLine: {
              show: false,
              lineStyle: {
                color: this.gray_colors[0],
                type: "dotted",
                opacity: 0.5,
              },
            },
            axisTick: {
              inside: false,
            },
            gridIndex: 0,
            axisLabel: {
              inside: false,
              color: this.gray_colors[1],
              fontSize: this.font_size,
              formatter: function (value) {
                let after = value - vue.OFFSETS[i];
                if (String(after).length > 5) {
                  after = Number(after).toFixed(
                    String(vue.MIN_MAX_ORDER[i].order).length - 1
                  );
                }
                return after;
              },
            },
            min: (() => {
              let min_max = this.MIN_MAX_ORDER[i];
              try {
                let order = this.ORDERs_OF_LINE[i];
                // debugger;
                return (
                  order * (Math.ceil(min_max.min / order) - 1) + this.OFFSETS[i]
                );
              } catch (e) {
                return null;
              }
            })(),
            max: (() => {
              let min_max = this.MIN_MAX_ORDER[i];
              try {
                let order = this.ORDERs_OF_LINE[i];
                // debugger;
                return (
                  order * (Math.floor(min_max.max / order) + 1) +
                  this.OFFSETS[i]
                );
              } catch (e) {
                return null;
              }
            })(),
            scale: true,
            splitNumber: 3,
            name: `{name|${attr}}`,
            nameGap: 60,
            nameRotate: 90,
            nameLocation: "center",
            nameTextStyle: {
              color: this.trend_colors[i],
              shadowColor: "red",
              shadowBlur: 1,
              fontSize: this.font_size,
              rich: {
                name: {
                  align: "center",
                },
              },
            },
          };
        })
        .concat([
          {
            gridIndex: 1,
            show: false,
          },
        ]);
    },
    opt_line_serieses() {
      let vue = this;
      return this.line_points.map((points, i) => {
        return {
          name: this.attrs[i],
          type: "line",
          data: points.map((e) => [e.test_id, e.value + this.OFFSETS[i]]),
          smooth: true,
          itemStyle: {
            color: function (params) {
              let dataIdx = params.dataIndex;
              let gap = parseInt(points.length / 10);
              if (dataIdx % gap == 0) {
                return vue.trend_colors[i];
              } else {
                return "transparent";
              }
            },
            borderWidth: 0,
          },
          yAxisIndex: i,
          symbol: i % 2 ? "rect" : "triangle",
          showSymbol: false,
          symbolSize: 10,
          showAllSymbol: false,
          lineStyle: {
            type: "solid",
            shadowColor: "rgba(0, 0, 0, 0.5)",
            width: 1.5,
            shadowBlur: 0,
            color: this.trend_colors[i],
          },
        };
      });
      //
    },
    opt_wugongtui() {
      let vue = this;
      return this.line_points.map((line_arr, line_index) => {
        return {
          type: "custom",
          name: this.attrs[line_index],
          yAxisIndex: line_index,
          data: this.wugong_data[line_index]
            .map((w, i) => {
              let testid = w["test_id"];
              let base_value = line_arr.find((x) => x["test_id"] == testid)[
                "value"
              ];
              let skew_value = 0.5 * vue.func_cv2value(w["cv"], line_index);
              if (w["skew"] < 0) {
                skew_value = skew_value * -1;
              }
              if (w["skew"] == 0) {
                skew_value = 0;
              }
              return [
                testid,
                base_value + this.OFFSETS[line_index],
                skew_value,
                w["skew"],
              ];
            })
            .filter((e, i) => i % 5),
          renderItem: function (params, api) {
            let [value0, value1, value2, value3] = [0, 1, 2, 3].map((e) =>
              api.value(e)
            );
            let coorded1 = api.coord([value0, value1]);
            let coorded2 = api.coord([value0, value1 + value2]);
            let sized = api.size([value0, value1]);
            return {
              type: "group",
              children: [
                {
                  type: "circle",
                  shape: {
                    cx: coorded1[0],
                    cy: coorded1[1],
                    r: 1,
                  },
                  style: {
                    fill: vue.trend_colors[line_index],
                  },
                },
                {
                  type: "line",
                  shape: {
                    x1: coorded1[0],
                    y1: coorded1[1],
                    x2: coorded1[0],
                    y2: coorded2[1],
                  },
                  style: {
                    fill: vue.trend_colors[line_index],
                    stroke:
                      line_index == 0
                        ? "rgba(69, 243, 156, 0.3)"
                        : "rgba(212, 109, 106, 0.3)" ||
                          vue.func_colorChangeLightness(
                            vue.trend_colors[line_index],
                            61
                          ),
                    lineWidth: (($) => {
                      let skew = value3;
                      let max_skew = vue.MAX_SKEWs[line_index];
                      let min_skew = vue.MIN_SKEWs[line_index];
                      let width =
                        ((skew - min_skew) / (max_skew - min_skew)) * 3 + 0.5;
                      if (width < 0) {
                        debugger;
                      }
                      return width;
                    })(),
                  },
                },
              ],
            };
          },
        };
      });
      //
    },
    opt_fake_xAxis_series() {
      let vue = this;
      let calced_lengthOfLinePoints = this.calced_lengthOfLinePoints;
      let gap = parseInt(this.calced_lengthOfLinePoints / 5);
      let order = this.orderOfMagnitude(gap);
      gap = Math.ceil(gap / order) * order;
      let count_tick = parseInt(this.calced_lengthOfLinePoints / gap) + 1;

      return [
        {
          type: "custom",
          name: "",
          yAxisIndex: 0,
          xAxisIndex: 0,
          data: _.range(0, count_tick).map((i) => {
            return [i * gap, 0 * 1.5];
          }),
          renderItem: function (params, api) {
            let [valuex, valuey] = [0, 1].map((e) => api.value(e));
            let coorded = api.coord([valuex, valuey]);
            let sized = api.size([valuex, valuey]);
            // debugger;
            return {
              type: "group",
              children: [
                {
                  type: "circle",
                  shape: {
                    cx: coorded[0],
                    cy: params.coordSys.y,
                    r: 0,
                  },
                  style: {
                    fill: "blue",
                  },
                  comment: "测试效果位置用",
                },
                {
                  type: "line",
                  shape: {
                    x1: coorded[0],
                    y1: params.coordSys.y + params.coordSys.height,
                    x2: coorded[0],
                    y2: params.coordSys.y + params.coordSys.height + 5,
                  },
                  style: {
                    // fill: vue.gray_colors[0],
                    stroke: vue.gray_colors[0],
                  },
                  lineWidth: 1,
                  //params.coordSys.y
                },
                {
                  type: "text",
                  style: {
                    x: coorded[0],
                    y: params.coordSys.y + params.coordSys.height + 7,
                    text: valuex + "",
                    textAlign: "center",
                    font: `11px "Microsoft Yahei", sans-serif`,
                    fill: vue.gray_colors[1],
                    stroke: vue.gray_colors[1],
                  },
                },
              ],
            };
          },
        },
        {
          type: "custom",
          name: "",
          yAxisIndex: 0,
          xAxisIndex: 0,
          data: [[(count_tick - 1) * gap, 0]],
          renderItem: function (params, api) {
            let [valuex, valuey] = [0, 1].map((e) => api.value(e));
            let coorded = api.coord([valuex, valuey]);
            let sized = api.size([valuex, valuey]);
            return {
              type: "group",
              children: [
                {
                  type: "line",
                  shape: {
                    x1: params.coordSys.x,
                    y1: params.coordSys.y + params.coordSys.height,
                    x2: params.coordSys.x + params.coordSys.width, //coorded[0],
                    y2: params.coordSys.y + params.coordSys.height,
                  },
                  style: {
                    // fill: vue.gray_colors[0],
                    stroke: vue.gray_colors[0],
                  },
                  lineWidth: 1,
                },
              ],
            };
          },
        },
      ];
    },
    func_colorChangeLightness() {
      /**@param {String} hexColor
       *@param {Number} L */
      function __func_change_color_lightness(hexColor, L) {
        let c = color(hexColor);
        let hslc = c.hsl();
        hslc = hslc.lightness(L);
        return hslc.hex();
      }
      return __func_change_color_lightness;
    },
    opt_belts() {
      return _.flatten(
        this.line_points.map((line_arr, line_index) => {
          return [
            {
              type: "line",
              name: this.attrs[line_index],
              stack: "belt" + this.attrs[line_index],
              data: (($) => {
                let data = this.wugong_data[line_index].map((w, i) => {
                  let value =
                    line_arr.find((x) => x["test_id"] == w["test_id"])[
                      "value"
                    ] -
                    this.func_cv2value(w["cv"], line_index) / 2;
                  return [w["test_id"], value + this.OFFSETS[line_index]];
                });
                return data;
              })(),
              symbolSize: 0,
              yAxisIndex: line_index,
              areaStyle: {
                color: "transparent",
              },
              itemStyle: {
                color: this.trend_colors[line_index],
              },
              lineStyle: {
                color: this.func_colorChangeLightness(
                  this.trend_colors[line_index],
                  71
                ),
                opacity: 0.2,
              },
              comment: "下边界",
            },
          ].concat([
            {
              type: "line",
              name: this.attrs[line_index],
              stack: "belt" + this.attrs[line_index],
              data: (($) => {
                let data = this.wugong_data[line_index].map((w, i) => {
                  let value = this.func_cv2value(w["cv"], line_index);
                  return [w["test_id"], value];
                });
                return data;
              })(),
              symbolSize: 0,
              yAxisIndex: line_index,
              areaStyle: {
                color: this.func_colorChangeLightness(
                  this.trend_colors[line_index],
                  71
                ),
                opacity: 0.2,
              },
              itemStyle: {
                color: this.trend_colors[line_index],
              },
              lineStyle: {
                color: this.func_colorChangeLightness(
                  this.trend_colors[line_index],
                  71
                ),
                opacity: 0.2,
              },
              comment: "上边界",
            },
          ]);
        })
      );
      //
    },
    opt_grids() {
      return [
        {
          left: 100,
          right: 100,
          top: 40,
          bottom: 60,
          show: false,
        },
        {
          left: 100,
          right: 100,
          // top: 174,
          height: 60 + 10,
          bottom: -10,
          show: false,
        },
      ];
    },
  },
  async mounted() {
    let vue = this;
    let chart = echarts.init(this.$refs["ele"]);
    this.chart = chart;
    // debugger
    this.clickLoad1();
  },
  methods: {
    async loadData(p1 = "/i50_max_msec.json", p2 = "/i50_max.json") {
      let dataTest1 = (await axios.get(p1)).data;
      let dataTest2 = (await axios.get(p2)).data;
      let raw_datas = [dataTest1, dataTest2];
      this.attrs = raw_datas.map((e) => _.keysIn(e.attributes_data)[0]);
      let ddd = raw_datas.map((e) => _.valuesIn(e.attributes_data)[0]);
      this.line_points = ddd.map((e) => e.points);
      this.wugong_data = ddd.map((e) => {
        let w_arr = e.centipede;
        let lastOne = w_arr[w_arr.length - 1];
        w_arr.push({
          cv: lastOne.cv,
          skew: lastOne.skew,
          test_id: e.points[e.points.length - 1]["test_id"],
        });
        return w_arr;
      });
      // debugger;
      this.chart.clear();
      this.chart.setOption({
        animation: false,
        grid: this.opt_grids,
        xAxis: this.opt_xAxis,
        yAxis: this.opt_yAxis,
        series: [
          ...this.opt_line_serieses,
          ...this.opt_wugongtui,
          ...this.opt_belts,
          ...this.opt_fake_xAxis_series,
        ],
      });
    },
    clickLoad1() {
      this.loadData("/i50_max_msec.json", "/i50_max.json");
    },
    clickLoad2() {
      this.loadData("/i50_integration.json", "/i30_integration.json ");
    },
    clickLoad3() {
      this.loadData("/i30_fall_msec.json", "/i30_fall_msec_speed.json");
    },
    clickLoad4() {
      this.loadData("/i30_extremum.json ", "/i30_max_msec.json");
    },
  },
};
</script>
<style lang="less" scoped>
.trend {
  @height: 234px;
  height: @height;
  position: relative;
  .canvas-parent {
    width: 1311px;
    height: @height;
  }
}
</style>